package pt.iscte.pcd.project.server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.util.Iterator;
import java.util.LinkedList;

import pt.iscte.pcd.project.local.LocalFile;
import pt.iscte.pcd.project.order.Order;
import pt.iscte.pcd.project.recursoPartilhado.ListaDeFicheiros;


public class DealWithClient {
	private Socket socketClient;
	private ObjectInputStream in;
	private ObjectOutputStream out;
	private LinkedList<Order> listaParaEnviar = new LinkedList<Order>();
	private LinkedList<Order> listaAReceber = new LinkedList<Order>();
	private DealWithClientReceiver threadDealWithClientReceiver;
	private DealWithClientSender threadDealWithClientSender;
	private ListaDeFicheiros listFiles;
	
	private LinkedList<LocalFile> readingFiles = new LinkedList<>();
	private LinkedList<LocalFile> writingFiles = new LinkedList<>();
	private LinkedList<DealWithClient> onlineUsers;
	
	private LinkedList<ServerWorker> threadsInWait  = new LinkedList<ServerWorker>();
	
	
	public DealWithClient(Socket socketClient, ListaDeFicheiros listFiles, LinkedList<DealWithClient> onlineUsers) {
		this.socketClient = socketClient;
		this.setOnlineUsers(onlineUsers);
		this.setListFiles(listFiles);
		try {
			setIn(new ObjectInputStream(getSocketClient().getInputStream()));
			setOut(new ObjectOutputStream(getSocketClient().getOutputStream()));
			threadDealWithClientReceiver = new DealWithClientReceiver(this);
			threadDealWithClientSender = new DealWithClientSender(this);
			threadDealWithClientSender.start();
			threadDealWithClientReceiver.start();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
	}
	

	/**
	 * Remove o ficheiro da lista de ficheiros a ler
	 * @param file
	 */
	public void removeReadingFile(LocalFile file){
		Iterator<LocalFile> itFiles = getReadingFiles().iterator();
		while(itFiles.hasNext()){
			LocalFile fileNext = itFiles.next();
			if(fileNext.getFullPath().equals(file.getFullPath())){
				itFiles.remove();
				break;
			}
		}
	}
	
	/**
	 * Remove o ficheiro da lista de ficheiros a escrever
	 * @param file
	 */
	public synchronized void removeWritingFile(LocalFile file){
		Iterator<LocalFile> itFiles = getWritingFiles().iterator();
		while(itFiles.hasNext()){
			LocalFile fileNext = itFiles.next();
			if(fileNext.getFullPath().equals(file.getFullPath())){
				itFiles.remove();
				break;
			}
		}
	}
	
	public void broadcastMessage(Order order) {
		for (DealWithClient c : getOnlineUsers()) {
			c.adicionaPedidoAEnviar(order);
		}
	}
	

	public synchronized LinkedList<LocalFile> getWritingFiles() {
		return writingFiles;
	}


	public synchronized LinkedList<LocalFile> getReadingFiles() {
		return readingFiles;
	}


	public Socket getSocketClient() {
		return socketClient;
	}


	public void setSocketClient(Socket socketClient) {
		this.socketClient = socketClient;
	}

	public ObjectInputStream getIn() {
		return in;
	}

	public void setIn(ObjectInputStream in) {
		this.in = in;
	}

	public ObjectOutputStream getOut() {
		return out;
	}

	public void setOut(ObjectOutputStream out) {
		this.out = out;
	}

	public synchronized Order retiraPedidoParaEnviar() throws InterruptedException {
		while(listaParaEnviar.isEmpty()){
			wait();
		}
		return listaParaEnviar.poll();
	}
	
	public synchronized Order retiraPedidoAReceber() throws InterruptedException {
		while(listaAReceber.isEmpty()){
			wait();
		}
		return listaAReceber.poll();
	}

	public synchronized void adicionaPedidoAEnviar(Order e) {
		listaParaEnviar.add(e);
		notifyAll();
	}

	public synchronized void adicionaPedidoAReceber(Order e) {
		listaAReceber.add(e);
		notifyAll();
	}


	public ListaDeFicheiros getListFiles() {
		return listFiles;
	}

	public void setListFiles(ListaDeFicheiros listFiles) {
		this.listFiles = listFiles;
	}


	public synchronized LinkedList<DealWithClient> getOnlineUsers() {
		return onlineUsers;
	}


	public void setOnlineUsers(LinkedList<DealWithClient> onlineUsers) {
		this.onlineUsers = onlineUsers;
	}


	public synchronized LinkedList<ServerWorker> getThreadsInWait() {
		return threadsInWait;
	}


	public void setThreadsInWait(LinkedList<ServerWorker> threadsInWait) {
		this.threadsInWait = threadsInWait;
	}


	public synchronized void removeThreadInWait(ServerWorker serverWorker) {
		Iterator<ServerWorker>  it = getThreadsInWait().iterator();
		while (it.hasNext()) {
			ServerWorker serverWorker2 = (ServerWorker) it.next();
			if (serverWorker.equals(serverWorker2)) {
				it.remove();
			}
		}
		
	}


	
}
